import { DataTypeInterface, DataType } from './DataType'
import { DataFormat, HttpMethod } from '../router'

export interface ModelMeta {
  name: string
  description: string
  isCreateTag?: boolean
  isCreateModel?: boolean
  modelPropertyMetaList?: ModelPropertyMeta[]
}

export interface ModelPropertyMeta {
  description: string
  type: DataTypeInterface
  default?: any
  property?: string
}

export function getModelMeta(constructor: Function): ModelMeta {
  return constructor.prototype.$ModelMeta || (constructor.prototype.$ModelMeta = {
    name: '',
    description: '',
    isCreateTag: true,
    isCreateModel: true,
    modelPropertyMetaList: []
  } as ModelMeta)
}

export interface PathMeta {
  path: string
  tags: string[]
  operationMetaList?: OperationMeta[]
}

export interface OperationMeta {
  path: string
  methodName?: string
  summary: string
  description?: string
  httpMethod?: HttpMethod
  dataFormat?: DataFormat
  parameterModel?: ParamMeta
  parameterList?: ParamMeta[]
  responseModel?: ParamMeta
  responseList?: ParamMeta[]
}

export type InValues = 'body' | 'header' | 'formData' | 'query' | 'path'

export interface ParamMeta {
  name?: string
  description?: string
  required?: boolean
  type?: DataTypeInterface
  in?: InValues
  default?: any
}

export function getPathMeta(constructor: Function): PathMeta {
  return constructor.prototype.$PathMeta || (constructor.prototype.$PathMeta = {
    path: '',
    tags: [],
    operationMetaList: []
  } as PathMeta)
}

export function getOperationMeta(target: Object, methodName: string): OperationMeta {
  const pathMeta = getPathMeta(target.constructor)

  const findObj = pathMeta.operationMetaList.find(item => item.methodName === methodName)

  if (findObj) {
    return findObj
  } else {
    const newObj: OperationMeta = {
      methodName: methodName,
      path: '',
      summary: '',
      dataFormat: DataFormat.JSON,
      parameterModel: null,
      parameterList: [],
      responseModel: null,
      responseList: []
    }

    pathMeta.operationMetaList.push(newObj)

    return newObj
  }
}

export function getParamMeta(options: ParamMeta) {
  return Object.assign({
    description: '',
    required: false,
    type: DataType.String
  } as ParamMeta, options)
}

